Avoiding Pitfalls

Things To Avoid While First Learning Python

15 March 2004


Contents

Hooks

When reviewing other people's code in the beginning, just skip anything with a name like __get_attr__ or __iter__. As with C, C++ or Assembler, leading underscores usually indicate voodoo happens here, so just make note of it for future explorations.

These bits are best avoided in the beginning.

They provide very powerful controls and offer rather elegant solutions for your top-level code. (Hint: you'll rarely see such functions or variables invoked directly, except usually by other routines with names involving leading underscores.)

As tutorials reveal certain methods such as __init__() or __str__(), feel free to begin using them at that time.

Predefined Class Variables Are Static Values

Assigning values to class attributes (think: class member fields from C++, Java) is akin to creating static values.

Consider this example.

>>> class Breakfast:
...     serving = ["spam & eggs", "toast"]
...     skipping = []
...     ordered = None
...

If you have more than one instance of Breakfast, both will access the same lists.

>>> alice = Breakfast()
>>> bob = Breakfast()
>>>

Not only do they have identical contents...

>>> bob.serving == alice.serving
True
>>>

Both reference the exact same object!

>>> bob.serving is alice.serving
True
>>>

So then, appending the list of what Bob is skipping with his breakfast order effects Alice's too, even though it might be only Bob who wants spam & eggs without the spam.

>>> bob.skipping.append("spam")
>>> alice.skipping
['spam']
>>>

The above subtlety applies to any pre-assigned value other than None.

>>> bob.ordered = 1
>>> print alice.ordered
None
>>>

As Python permits creating class attributes "on demand" unlike compiled object oriented languages, you can identify unshared fields by assigning a value of None (think: NULL).

class Breakfast:
    serving = ["spam & eggs", "toast"]
    skipping = None
    ordered = None

def __init__(self):
        self.skipping = []

Or if you prefer more concise code:

class Breakfast:
    self.serving = ["spam & eggs", "toast"]

    def __init__(self):
        self.skipping = []
        self.ordered = None

(And yes, there are ways to avoid inadvertently creating class variables, such as those created by typing errors in one's code. Though, a programming editor with word completion works even better. In Emacs, use ALT-/ much like using Tab key in Bash shell to attempt completing the current word.)